#include "net_server.h"

NetServer::NetServer(const string &ip, short port)
    : ip_(ip), port_(port)
{
    sfd_ = init_();
    ERR_CHECK(sfd_, -1, "init_");

    // 将sfd加到epoll监听队列中
    addEpfd(sfd_);
    // 创建信号描述符，当接受到2号信号时，结束进程
    sigfd_ = initSig_();
    ERR_CHECK(sigfd_, -1, "initSig_")
    addEpfd(sigfd_);

    // 初始化线程池(为了使所有线程继承主线程的信号)
    threadPoll_ = new ThreadPoll(5, 10);

#ifdef DEBUG
    addEpfd(STDIN_FILENO);
#endif
}

NetServer::~NetServer()
{
    ::close(sfd_);
    if (threadPoll_)
        delete threadPoll_;
}

void NetServer::start()
{
    bool isRunning = true;
    struct Protocol proto{};
    struct epoll_event evts[EPOLL_EVENT_LEN]{};
    int readyNum{};
    while (isRunning)
    {
        readyNum = epoll_wait(epfd_, evts, EPOLL_EVENT_LEN, -1);
        for (int i{}; i < readyNum; i++)
        {
            // 有新的客户端连接请求
            if (evts[i].data.fd == sfd_)
            {
                acceptNewfd();
            }
#ifdef DEBUG
            else if (evts[i].data.fd == STDIN_FILENO)
            {
                int ret = ::read(STDIN_FILENO, proto.buf_, PROTOCOL_BUF_LEN);
                ERR_CHECK(ret, -1, "start read")

                ret = ::send(5, proto.buf_, sizeof(proto.buf_), 0);
                ERR_CHECK(ret, -1, "start write")
                cout << proto.buf_ << endl;
            }
#endif
            else if (evts[i].data.fd == sigfd_)
            {
                struct signalfd_siginfo info{};
                int ret = ::read(sigfd_, &info, sizeof(info));
                if (info.ssi_signo == SIGINT)
                {
                    isRunning = false;
                    cout << "\rserver is shutdown..." << endl;
                }
            }
            else
            {
                handleRequest(evts[i].data.fd);
            }
        }
    }
}

void NetServer::acceptNewfd()
{
    int newfd = ::accept(sfd_, nullptr, nullptr);
    ERR_CHECK(newfd, -1, "accept")
    addEpfd(newfd);

    // 将新连接加入到tcpMp 中
    tcpMp_[newfd] = std::make_shared<TcpConnect>(newfd, threadPoll_);

    cout << "new connection: " << tcpMp_[newfd]->getPeer() << endl;
}

void NetServer::handleRequest(int fd)
{
    // 处理请求 : 断开连接返回 -1
    IsClose isClosed = tcpMp_[fd]->handleRequest();
    if (isClosed == IsClose::TRUE)
    {
        close(fd);
        ::close(fd);
        // 如果是半关闭，那么就删除监听和tcpConnect，将文件描述符交给子线程处理
    }
    else if (isClosed == IsClose::HALF)
    {
        close(fd);
    }
}

void NetServer::close(int fd)
{
    delEpfd(fd);
    tcpMp_.erase(fd);
}

bool NetServer::isClose(int fd)
{
    return tcpMp_[fd]->isClose();
}

int NetServer::init_()
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    ERR_CHECK_RETURN(fd, -1, "socket");

    struct sockaddr_in sock{};
    sock.sin_addr.s_addr = inet_addr(ip_.c_str());
    sock.sin_port = htons(port_);
    sock.sin_family = AF_INET;

    int reuse = 1;
    int ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
    ERR_CHECK_RETURN(ret, -1, "setsockopt");

    ret = bind(fd, (struct sockaddr *)&sock, sizeof(sock));
    ERR_CHECK_RETURN(ret, -1, "bind");

    ret = listen(fd, 128);
    ERR_CHECK_RETURN(ret, -1, "listen");

    epfd_ = epoll_create(1);
    ERR_CHECK_RETURN(epfd_, -1, "epoll_create")

    return fd;
}

void NetServer::addEpfd(int fd)
{
    struct epoll_event evt{};
    evt.data.fd = fd;
    evt.events = EPOLLIN;

    int ret = epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &evt);
    ERR_CHECK(ret, -1, "epoll_ctl")
}

void NetServer::delEpfd(int fd)
{
    struct epoll_event evt{};
    evt.data.fd = fd;
    evt.events = EPOLLIN;

    epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, &evt);
}

int NetServer::initSig_()
{
    sigset_t mask;
    int ret = sigemptyset(&mask);
    ERR_CHECK_RETURN(ret, -1, "sigemptyset")
    ret = sigaddset(&mask, SIGINT);
    ERR_CHECK_RETURN(ret, -1, "sigaddset")

    ret = pthread_sigmask(SIG_BLOCK, &mask, nullptr);
    // ret = sigprocmask(SIG_BLOCK, &mask, nullptr);
    ERR_CHECK_RETURN(ret, -1, "sigprocmask")

    int sigfd = signalfd(-1, &mask, 0);
    ERR_CHECK_RETURN(sigfd, -1, "signalfd")
    return sigfd;
}